
#ifndef CSHARPPROPERTYMETHODS_H
#define CSHARPPROPERTYMETHODS_H

// Reference: http://stackoverflow.com/questions/151418/calling-a-c-function-pointer-on-a-specific-object-instance

// This variant of property is for custom Get and Set methods.
template<typename C, typename T> class Property2
{
	// Typedef for Get and Set.
	typedef void	(C::*method_in)( const T& );
	typedef T		(C::*method_out)();

private:
	// Function pointers for Get and Set.
	C* _property_parent;
	method_in _in;
	method_out _out;

public:
	//----------------------------------------
    Property2()
		: _property_parent( 0 )
		, _in( 0 )
		, _out( 0 )
    {
		//	      / \
		//	     // \\
		//	    // | \\
		//	   //  |  \\
		//    //   |   \\
		//   //    |    \\
		//  //           \\
		// //      O      \\
		// =================

		// If building fail. You must be sure that you have included the COPY_CONSTRUCTOR macro
		// for you class/struct and initialize allt properties if you have it.
#if _DEBUG
		_property_parent->_copy_constructor_decleration_check();
#endif
    }

	//----------------------------------------
    Property2( C* property_parent, method_in set_prop, method_out get_prop )
		: _property_parent( property_parent )
		, _in( set_prop )
		, _out( get_prop )
    {
		//	      / \
		//	     // \\
		//	    // | \\
		//	   //  |  \\
		//    //   |   \\
		//   //    |    \\
		//  //           \\
		// //      O      \\
		// =================

		// If building fail. You must be sure that you have included the COPY_CONSTRUCTOR macro
		// for you class/struct and initialize allt properties if you have it.
#if _DEBUG
		_property_parent->_copy_constructor_decleration_check();
#endif
    }

	//----------------------------------------
    Property2<C, T>& operator = (const T& val)
    {
		// Instance -> points to the pointed method ( parameter );
		(_property_parent->*_in)(val);
        return(*this);
    };

	//----------------------------------------
    Property2<C, T>& operator += (const T& val)
    {
		// Instance -> points to the pointed method ( Get_Method + parameter );
		(_property_parent->*_in)( (_property_parent->*_out)() + val );
        return(*this);
    };

	//----------------------------------------
    Property2<C, T>& operator -= (const T& val)
    {
		// Instance -> points to the pointed method ( Get_Method + parameter );
		(_property_parent->*_in)( (_property_parent->*_out)() - val );
        return(*this);
    };

	//----------------------------------------
    operator const T() const
    {
		//		Instance -> points to the pointed method ( no parameters );
		return (_property_parent->*_out)();
    };
	
	//----------------------------------------
	T operator *()
	{
		return (_property_parent->*_out)();
	}

	//----------------------------------------
	// This method is good for the foreach' machinery.
	T get()
	{
		return (_property_parent->*_out)();
	}
};

// This variant of property is for custom Get method.
template<typename C, typename T> class Property_Get
{
	// Typedef for Get and Set.
	typedef T		(C::*method_out)( void );

private:
	// Function pointers for Get and Set.
	C* _property_parent;
	method_out _out;

public:
	//----------------------------------------
    Property_Get()
		: _property_parent( 0 )
		, _out( 0 )
    {
		//	      / \
		//	     // \\
		//	    // | \\
		//	   //  |  \\
		//    //   |   \\
		//   //    |    \\
		//  //           \\
		// //      O      \\
		// =================

		// If building fail. You must be sure that you have included the COPY_CONSTRUCTOR macro
		// for you class/struct and initialize allt properties if you have it.
#if _DEBUG
		_property_parent->_copy_constructor_decleration_check();
#endif
    }

	//----------------------------------------
    Property_Get( C* property_parent, method_out get_prop )
		: _property_parent( property_parent )
		, _out( get_prop )
    {
		//	      / \
		//	     // \\
		//	    // | \\
		//	   //  |  \\
		//    //   |   \\
		//   //    |    \\
		//  //           \\
		// //      O      \\
		// =================

		// If building fail. You must be sure that you have included the COPY_CONSTRUCTOR macro
		// for you class/struct and initialize allt properties if you have it.
#if _DEBUG
		_property_parent->_copy_constructor_decleration_check();
#endif
    }
	
	//----------------------------------------
    operator const T() const
    {
		//		Instance -> points to the pointed method ( no parameters );
		return (_property_parent->*_out)();
    };
	
	//----------------------------------------
	T operator *()
	{
		return (_property_parent->*_out)();
	}

	//----------------------------------------
	// This method is good for the foreach' machinery.
	T get()
	{
		return (_property_parent->*_out)();
	}
};

// This variant of property is for custom Get and Set methods for static usage.
template<typename T> class StaticProperty2
{
	// Typedef for Get and Set.
	typedef void	(*method_in)( const T& );
	typedef T		(*method_out)( void );

private:
	// Function pointers for Get and Set.
	method_in _in;
	method_out _out;

public:
	//----------------------------------------
    StaticProperty2( method_in set_prop, method_out get_prop )
		: _in( set_prop )
		, _out( get_prop )
    {
    }

	//----------------------------------------
    StaticProperty2<T>& operator = (const T& val)
    {
		//	points to the pointed method ( parameter );
		_in(val);
        return(*this);
    }

	//----------------------------------------
    operator const T() const
    {
		//	points to the pointed method ( no parameters );
		return _out();
    }

	//----------------------------------------
    operator T()
	{
		//	points to the pointed method ( no parameters );
		return _out();
    }
	
	//----------------------------------------
	T operator *()
	{
		return _out();
	}

	//----------------------------------------
	T operator ->()
	{
		return _out();
	}
	
	//----------------------------------------
	// This method is good for the foreach' machinery.
	T get()
	{
		return _out();
	}
};

// This variant of property is for custom Get and Set methods for static usage.
template<typename T> class StaticProperty2_Get
{
	// Typedef for Get and Set.
	typedef T		(*method_out)( void );

private:
	// Function pointers for Get and Set.
	method_out _out;

public:
	//----------------------------------------
    StaticProperty2_Get( method_out get_prop )
		: _out( get_prop )
    {
    }

	//----------------------------------------
    StaticProperty2_Get<T>& operator = (const T& val)
    {
		//	points to the pointed method ( parameter );
		_in(val);
        return(*this);
    }

	//----------------------------------------
    operator const T() const
    {
		//	points to the pointed method ( no parameters );
		return _out();
    }

	//----------------------------------------
    operator T()
	{
		//	points to the pointed method ( no parameters );
		return _out();
    }
	
	//----------------------------------------
	T operator *()
	{
		return _out();
	}

	//----------------------------------------
	T operator ->()
	{
		return _out();
	}
	
	//----------------------------------------
	// This method is good for the foreach' machinery.
	T get()
	{
		return _out();
	}
};

// MACROS.

// Get set.
#define PROP3_DEF( OwnerClass, Type, name ) Property2<OwnerClass, Type> name;
#define PROP3( OwnerClass, Type, name ) protected: Type _PROP_##name; public: PROP3_DEF(OwnerClass, Type, name )
#define PROP3_INIT( OwnerClass, name ) name ( this, &OwnerClass::_Set_##name, &OwnerClass::_Get_##name )
#define PROP3_INIT_COPY( OwnerClass, Type, name ) name = Property2<OwnerClass, Type>( this, &OwnerClass::_Set_##name, &OwnerClass::_Get_##name )

// Get.
#define PROP3GET_DEF( OwnerClass, Type, name ) Property_Get<OwnerClass, Type> name;
#define PROP3GET( OwnerClass, Type, name ) protected: Type _PROP_##name; public: PROP3GET_DEF(OwnerClass, Type, name )
#define PROP3GET_INIT( OwnerClass, name ) name ( this, &OwnerClass::_Get_##name )
#define PROP3GET_INIT_COPY( OwnerClass, Type, name ) name = Property_Get<OwnerClass, Type>( this, &OwnerClass::_Get_##name )

// Static get set.
#define PROP3_STATIC_DEF( OwnerClass, Type, name ) static StaticProperty2< Type > name;
#define PROP3_STATIC( OwnerClass, Type, name ) private: static Type _PROP_##name; public: PROP3_STATIC_DEF(OwnerClass, Type, name )
#define PROP3_STATIC_INIT( OwnerClass, Type, name ) StaticProperty2< Type > OwnerClass::name( &OwnerClass::_Set_##name, &OwnerClass::_Get_##name );

// Static get.
#define PROP3GET_STATIC_DEF( OwnerClass, Type, name ) static StaticProperty2_Get< Type > name;
#define PROP3GET_STATIC( OwnerClass, Type, name ) private: static Type _PROP_##name; public: PROP3GET_STATIC_DEF(OwnerClass, Type, name )
#define PROP3GET_STATIC_INIT( OwnerClass, Type, name ) StaticProperty2_Get< Type > OwnerClass::name( &OwnerClass::_Get_##name );
// If declare in H file.
#define PROP3_SET( Type, name ) void _Set_##name( const Type & value )
#define PROP3_GET( Type, name ) Type _Get_##name()

// If declare in CPP file.
#define PROP3_SET_CPP( OwnerClass, Type, name ) void OwnerClass::_Set_##name( const Type & value )
#define PROP3_GET_CPP( OwnerClass, Type, name ) Type OwnerClass::_Get_##name()

#endif // CSHARPPROPERTYMETHODS_H